#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
#include "Socket.hpp"
#include "log.hpp"
#include "epoller.hpp"
#include "Comm.hpp"
const int fd_num_max = sizeof(fd_set) * 8; // 4096
int defaultfd = -1;
uint16_t defaultport = 8080;
uint32_t EVENT_IN = (EPOLLIN | EPOLLET);
uint32_t EVENT_OUT = (EPOLLOUT|EPOLLET);


//对每一个链接进行专门管理
//管理读写异常等

//包装器
class Connection;//得事先声明，否则编译器不知道类型
class Reactor ;
using func_t =std::function<void(std::weak_ptr<Connection>)>; 
using except_func  =std::function<void(std::weak_ptr<Connection>)>;


class Connection
{
public:
    Connection(int sock)
    :_sock(sock)
    {

    }
    ~Connection()
    {}
    std::string &Inbuffer() // for debug
    {
        return _inbuffer;
    }
    std::string &OutBuffer()
    {
        return _outbuffer;
    }
    void SetWeakptr(std::weak_ptr<Reactor> Reactor_ptr)
    {
        _Reactor_ptr=Reactor_ptr;
    }

    // Connection 类对象设置用于处理不同网络事件的回调函数
    void SetHandler(func_t recv_cb, func_t send_cb, except_func except_cb)
    {
        _recv_cb = recv_cb;
        _send_cb = send_cb;
        _except_cb = except_cb;
    }


    int SockFd() { return _sock; }
    void AppendInBuffer(const std::string &info)
    {
        _inbuffer += info;
    }
    void AppendOutBuffer(const std::string &info)
    {
        _outbuffer += info;
    }

private:
    //链接的fd和各自的输入输出缓冲区
    int _sock;
    string _inbuffer;
    string _outbuffer;
    //


    //回指指针
    std::weak_ptr<Reactor> _Reactor_ptr;
public:
    std::string _ip;
    uint16_t _port;
    //
    func_t _recv_cb;
    func_t _send_cb;
    except_func _except_cb;
};


//public std::enable_shared_from_this<Reactor>指向自身的智能指针
class Reactor : public std::enable_shared_from_this<Reactor>,public nocopy
{
public:
    Reactor(uint16_t port = defaultport)
        : _port(port)
        , _listsocket_ptr(new Sock())
        , _epoller_ptr(new epoller())
    {
    }
    ~Reactor()
    {
        _listsocket_ptr->Close();
    }
    void Init()
    {
        _listsocket_ptr->Socket();
        //设置为非阻塞
        SetNonBlockOrDie(_listsocket_ptr->get_sockfd());
        _listsocket_ptr->Bind(_port);
        _listsocket_ptr->Listen();

        lg(Info, "create listen socket success: %d\n", _listsocket_ptr->get_sockfd());

        //对每一个链接进行单独管理，包括最开始的链接  
        //epoll机制会监听这个fd,当有链接来时就会回调函数  Accepter
        AddConnection(_listsocket_ptr->get_sockfd(),
                      EVENT_IN, std::bind(&Reactor::Accepter, this, std::placeholders::_1), nullptr, nullptr);
    }


    void AddConnection(int sock, uint32_t event, func_t recv_cb, func_t send_cb, except_func except_cb,
                       const std::string &ip = "0.0.0.0", uint16_t port = 0)
    {
        //建立connection类
        std::shared_ptr<Connection> new_connection(new Connection(sock));
        new_connection->SetWeakptr(shared_from_this());   //指向该类的shared
        new_connection->SetHandler(recv_cb, send_cb, except_cb);
        new_connection->_ip = ip;
        new_connection->_port = port;
        _connection.insert(std::make_pair(sock,new_connection));   //将fd和自身的connection类组成键值对

        //设置为非阻塞(这个在外面设置)
        //监听
        _epoller_ptr->Epoll_Update(EPOLL_CTL_ADD,sock,event);
        std::cout<<"sock "<<sock<<"port::%d "<<port<<"ip::%sdddddd"<<ip.c_str()<<std::endl;
    }


    //执行链接，并将链接后的client_fd也进行监听
    void Accepter(std::weak_ptr<Connection> conn)
    {
        uint16_t port;
        string ip;
        int sockfd=_listsocket_ptr->Accept(ip,&port);
        std::cout<<"sockfd::%d " <<sockfd<<"port::%d "<<port<<"ip::%s"<<ip.c_str()<<std::endl;
        if(sockfd>0)
        {
            //将通信用的fd设置为非阻塞
            SetNonBlockOrDie(sockfd);
            AddConnection(sockfd,EVENT_IN,std::bind(&Reactor::Reciver, this, std::placeholders::_1)
                                         ,std::bind(&Reactor::Sender, this, std::placeholders::_1)
                                         ,std::bind(&Reactor::Excepter, this, std::placeholders::_1)
                                         ,ip,port);
            std::cout<<"sockfd::%d \n" <<sockfd<<std::endl;
        }

    }

    //读就绪后接收消息
    void Reciver(std::weak_ptr<Connection> conn)
    {
        //判断对象是否被销毁 
        std::cout<<"xxxxx"<<std::endl;
        if(conn.expired()) return;
        //通过 connection（一个 std::weak_ptr）获取一个 std::shared_ptr，这个 std::shared_ptr 指向 Connection 对象
        auto connection = conn.lock();
        char buffer[1024];
        //非阻塞读
        while(true)
        {
            //recv();
            memset(buffer,0,sizeof(buffer));
            //int n=read(connection->SockFd(),buffer,sizeof(buffer)-1);
            int n=recv(connection->SockFd(),buffer,sizeof(buffer)-1,0);
            std::cout<<buffer<<"xxxxx"<<std::endl;
            if(n>0)
            {
                //存在对应connection的接收缓冲区
                connection->AppendInBuffer(buffer);
                std::cout<<buffer<<std::endl;
                PrintConnection();
            }
            //再关闭通信，先删除监听
            else if(n==0)
            {
                lg(Info, "sockfd: %d, client info %s:%d quit...", connection->SockFd(), connection->_ip.c_str(), connection->_port);
                //_epoller_ptr->Epoll_Update(EPOLL_CTL_DEL,connection->SockFd(),);
                connection->_except_cb(conn);
            }
            //异常处理 回调函数
            else
            {
                //读取被阻塞了，即数据读取完毕，等待数据到来，先退出，等待下次触发
                if (errno == EWOULDBLOCK)
                    break;
                //表示被中断了，中断完成后在返回继续读取
                else if (errno == EINTR)
                    continue;
                else
                {
                    lg(Warning, "sockfd: %d, client info %s:%d recv error...",  connection->SockFd(), connection->_ip.c_str(), connection->_port);
                    connection->_except_cb(connection);
                    return;
                }
            }
            // PrintConnection();
        }
       
        
    }

    //发送
    void Sender(std::weak_ptr<Connection> conn)
    {
        if(conn.expired()) return;
        auto connection = conn.lock();

        int fd=connection->SockFd();
        while(true)
        {
            // 0 是 send() 函数的第四个参数，表示标志位。send() 函数支持一些额外的选项和标志，
            // 如 MSG_OOB（发送带外数据）等。0 表示没有特殊的标志，用默认设置发送数据。
            int n=send(connection->SockFd(),connection->OutBuffer().c_str(),sizeof(connection->OutBuffer().size()),0);
            if(n>0)
            {
                //数据发送完了，及时清理缓冲区
                connection->OutBuffer().erase(0,n);  
                //connection->_send_cb(connection);
            }
            //可能对方关闭了链接，可以考虑删除监听
            else if(n==0)
            {
                return ;
            }
            else
            {
                if(errno == EWOULDBLOCK) break;
                else if(errno == EINTR) continue;
                else{
                    lg(Warning, "sockfd: %d, client info %s:%d send error...", connection->SockFd(), connection->_ip.c_str(), connection->_port);
                    connection->_except_cb(connection);
                    return;
                }
            }


            //检查缓冲区是否发送干净
            if(!connection->OutBuffer().empty())
            {
                //设置监听
                //_epoller_ptr->Epoll_Update(EPOLL_CTL_ADD,fd,EVENT_OUT);
                _epoller_ptr->Epoll_Update(EPOLL_CTL_MOD,fd,EVENT_OUT);
                
            }
            else
            {
                //取消监听
                _epoller_ptr->Epoll_Update(EPOLL_CTL_MOD,fd,0);
            }
        }

    }

    void Excepter(std::weak_ptr<Connection> conn)
    {
        if(conn.expired()) return;
        auto connection = conn.lock();

        int fd=connection->SockFd();
        _epoller_ptr->Epoll_Update(EPOLL_CTL_DEL,fd,0);
        close(fd);
        lg(Warning, "Excepter hander sockfd: %d, client info %s:%d excepter handler",
           connection->SockFd(), connection->_ip.c_str(), connection->_port);

        //再从connection移除
        _connection.erase(fd);  
    }


    //总体循环，分派任务
    void Loop()
    {
        while(true)
        {
            Dispatcher(3000);
            //PrintConnection();
        }
    }



    // void Start()
    // {
    //     // 这里只监听listensockfd
    //     int n = _epoller_ptr->Epoll_Update(EPOLL_CTL_ADD, _listsocket_ptr->get_sockfd(), EVENT_IN);
    //     struct epoll_event recv[num];
    //     while (1)
    //     {
    //         int n = _epoller_ptr->Epoll_Wait(recv, num);
    //         // 返回值n:返回对应I/O上已准备好的文件描述符数目，如返回0表示已超时, 返回小于0表示函数失败
    //         // recv保存等到的fd事件属性
    //         // 等到之后，分配任务
    //         if (n > 0)
    //         {
    //             // 有事件就绪
    //             lg(Debug, "event happened, fd is : %d", recv[0].data.fd);
    //             Dispatcher(recv, n);
    //         }
    //         else if (n == 0)
    //         {
    //             lg(Info, "time out ...");
    //         }
    //         else
    //         {
    //             lg(Error, "epll wait error");
    //         }
    //     }
    // }

    bool IsConnectionSafe(int fd)
    {
        auto iter = _connection.find(fd);
        if (iter == _connection.end())
            return false;
        else
            return true;
    }


    // num为等到的个数
    void Dispatcher( int num)
    {
        //返回的n是等到的fd数目
        int n = _epoller_ptr->Epoll_Wait(revs, num);
        for(int i=0;i<n;i++)
        {
            //从等待的revs中  分别进行处理
            uint32_t events = revs[i].events;
            int sock = revs[i].data.fd;

            /*
            EPOLLERR：表示发生了错误。
            EPOLLHUP：表示连接关闭或被挂起。
            由于在 epoll 中这两种事件通常被视为读写错误，
            因此将这两个事件的标志合并为 EPOLLIN | EPOLLOUT，这样就会将这些事件视为需要处理的读写问题。
            */
            if (events & EPOLLERR)
                events |= (EPOLLIN | EPOLLOUT);
            if (events & EPOLLHUP)
                events |= (EPOLLIN | EPOLLOUT);

            //读
            if(events==EVENT_IN&&IsConnectionSafe(sock))
            {
                if(_connection[sock]->_recv_cb)
                {
                    _connection[sock]->_recv_cb;
                    //std::cout <<"%d \n"<<&_connection[sock]->_recv_cb<<std::endl;
                }  
            }

            //写
            else if(events==EVENT_OUT&&IsConnectionSafe(sock))
            {
                if(_connection[sock]->_send_cb)
                {
                    _connection[sock]->_send_cb;
                     //std::cout <<"%d \n"<<&_connection[sock]->_send_cb<<std::endl;
                }
                   
            }

        }
    }


    void PrintConnection()
    {
        std::cout << "_connections fd list: ";
        for (auto &connection : _connection)
        {
            std::cout << connection.second->SockFd() << ", ";
            std::cout << "inbuffer: " << connection.second->Inbuffer().c_str();
        }
        std::cout << std::endl;
    }

    

private:
    std::shared_ptr<Sock> _listsocket_ptr;
    std::shared_ptr<epoller> _epoller_ptr;
    uint16_t _port;
    static const int num = 64;
    std::unordered_map<int,std::shared_ptr<Connection>> _connection;
    struct epoll_event revs[num];
};
